//4.变量对象VO

/*
* 执行上下文，都有三个重要属性：
* 变量对象(Variable object，VO)
* 作用域链(Scope chain)
* this
* */

//变量对象VO: 变量对象是与执行上下文相关的数据作用域，存储了在上下文中定义的变量和函数声明

/*
*  VO属性:
*  1.所有全局对象和函数声明
*  2.内置对象(Math,String,Data等)
*  3.全局函数(isNan,parseInt等)
*  4.在全局上下文中，this指向VO本身
* */

//VO类型：
/*
* 1.全局上下文VO: 即为全局对象，浏览器中为window
* 2.函数上下文VO(AO): VO 被称为活动对象（Activation Object, AO）
* 3.eval 上下文：根据 eval 代码所在位置决定
* */

//1.全局上下文VO:  在全局上下文中，VO 就是全局对象自身
  let globalVal = 'global';
  const globalFun = function (){};
  //相当于
  window.globalVal = 'global';
  window.globalFun = function (){};

//2.函数上下文VO(AO): 活动对象AO
//函数被调用时，会创建对应的 AO

//执行过程:创建阶段(代码执行前) + 代码执行

/*
* 创建阶段的 AO 属性（代码执行前）:
* 1.函数参数（Arguments）
* 2.函数声明（Function Declaration）
* 3.变量声明（Variable Declaration）
* */

/*
*  执行顺序规则：
*  1.建立 Arguments 对象:
*  创建 arguments 属性，值为 Arguments 对象
*  检查参数，初始化对应属性
*  2.扫描函数声明
*  找到所有 function 声明
*  在 VO 中以函数名创建属性，值为函数引用
*  如果函数名已存在，覆盖之前的属性
*  3.扫描变量声明
*  找到所有 var 声明
*  在 VO 中以变量名创建属性，值为 undefined
*  如果变量名已存在，不会覆盖（忽略重复声明）
*
* */

//示例1
function test(a,b){
    var x = 10;
    function inner(){}
    var y = 20;
}
test(1,2);
// 创建阶段
let AO

AO = {
    //1.函数参数 arguments
    arguments:{0:1,1:2,length:2,callee:test},
    a:1,
    b:2,
    //2.函数声明
   // inner: <function inner>,
    //3.变量声明
    x:undefined,
    y:undefined
}

//执行阶段：

AO = {
    arguments:{0:1,1:2,length:2,callee:test},
    a:1,
    b:2,
    // inner: <function inner>,
    x:10,   //赋值
    y:20   //赋值
}

//示例2:   函数声明优先于于变量声明

function example(){
    console.log(typeof foo);  //function
    console.log(typeof bar); //undefined
    function foo(){};
    var bar = function (){};
    console.log(typeof bar);  //function
}

example();

AO = {
    //函数声明优先
    // foo: <function foo >,
    //变量声明
    bar:undefined,
}
/*
* 第一个 console.log：foo 是函数，bar 是 undefined
* 执行赋值后：bar 变为函数
* */

//示例3: 重复名称的处理

function  duplicate(){
    console.log(typeof func);  //function
    console.log(typeof varFunc);  //undefined
    function func(){};
    var varFunc = 'variable';
    function func(){ return "new" };//覆盖
    console.log(func());  //new
    console.log(varFunc);  //variable
}
duplicate();
AO = {
    //函数声明覆盖
    // func:<function func>,
    // 变量声明（不覆盖函数）
    varFunc :undefined,
}


//示例4: VO/AO 是内部机制，不能在代码中直接访问
function showVOIndirectly(a, b) {
    // 通过 arguments 可看到参数
    console.log(arguments);

    // 通过变量访问可看到值
    var test = "value";
    console.log(test);  // "value"

    // 但不能直接访问 VO 对象本身
    // console.log(VO);  // 会报错
}

//示例5: VO 是作用域链中的重要一环
var global = 'global';
function  outer(){
     var outerVar = 'outer';
     function inner(){
         var innerVar = 'inner';
         console.log(innerVar);   // 当前VO
         console.log(outerVar);   // outerVal的VO
         console.log(global);     //  全局VO
     }
    inner();
}
outer();

// inner函数的作用域链
/*
*  [0]: inner AO
*  [1]: outer AO
*  [2]: global VO
*  查找变量时，沿着作用域链依次检查各个 VO
* */


// VO总结:
/*
*  1.存储结构:存储了当前上下文中的所有变量和函数声明
*  2.创建顺序: 参数===》函数====》变量声明
*  3.重复处理:函数声明覆盖，变量声明不覆盖
*  4.不同类型:全局VO是全局对象，函数VO是AO
*  5.内部机制:AO/VO不能直接访问，但能决定变量查找行为(作用域链)
* */